<!DOCTYPE html>
<html lang="zh_cn">
<head>
          <title>来玩魔王的咚</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta charset="utf-8" />
        <!-- twitter card metadata -->
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="/images/mowang.png">
<meta name="twitter:site" content="">
<meta name="twitter:title" content="JSON、文本模板、HTML模板">
<meta name="twitter:description" content="<p>JSON：序列化，成员标签，反序列化；HTTP获取JSON：获取GitHub的issue信息，流式解码；文本模板：模板表达式，模板输出的过程，帮助函数Must；HTML模板：输出网页，template.HTML类型避免转义。</p>">
        <!-- OG Tags -->
<meta property="og:url" content="/gopl-json-template-html.html"/>
<meta property="og:title" content="来玩魔王的咚 | JSON、文本模板、HTML模板" />
<meta property="og:description" content="<p>JSON：序列化，成员标签，反序列化；HTTP获取JSON：获取GitHub的issue信息，流式解码；文本模板：模板表达式，模板输出的过程，帮助函数Must；HTML模板：输出网页，template.HTML类型避免转义。</p>" />
        <!-- favicon -->
        <link rel="icon" type="image/png" href="/images/mowang.png">
        <!-- moment.js for date formatting -->
        <script src="/theme/js/moment.js"></script>
        <!-- css -->
        <link rel="stylesheet" type="text/css" href="/theme/css/main.css" />
        <!-- 左边的menu，如果页面高度不够，就跟着滚动，否则文章分类显示不全 -->
        <link rel="stylesheet" type="text/css" href="/theme/css/mycss/menu.css" />
		<script>
			
                /*! grunt-grunticon Stylesheet Loader - v2.1.2 | https://github.com/filamentgroup/grunticon | (c) 2015 Scott Jehl, Filament Group, Inc. | MIT license. */
    
    (function(e){function t(t,n,r,o){"use strict";function a(){for(var e,n=0;u.length>n;n++)u[n].href&&u[n].href.indexOf(t)>-1&&(e=!0);e?i.media=r||"all":setTimeout(a)}var i=e.document.createElement("link"),l=n||e.document.getElementsByTagName("script")[0],u=e.document.styleSheets;return i.rel="stylesheet",i.href=t,i.media="only x",i.onload=o||null,l.parentNode.insertBefore(i,l),a(),i}var n=function(r,o){"use strict";if(r&&3===r.length){var a=e.navigator,i=e.Image,l=!(!document.createElementNS||!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect||!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")||e.opera&&-1===a.userAgent.indexOf("Chrome")||-1!==a.userAgent.indexOf("Series40")),u=new i;u.onerror=function(){n.method="png",n.href=r[2],t(r[2])},u.onload=function(){var e=1===u.width&&1===u.height,a=r[e&&l?0:e?1:2];n.method=e&&l?"svg":e?"datapng":"png",n.href=a,t(a,null,null,o)},u.src="",document.documentElement.className+=" grunticon"}};n.loadCSS=t,e.grunticon=n})(this);(function(e,t){"use strict";var n=t.document,r="grunticon:",o=function(e){if(n.attachEvent?"complete"===n.readyState:"loading"!==n.readyState)e();else{var t=!1;n.addEventListener("readystatechange",function(){t||(t=!0,e())},!1)}},a=function(e){return t.document.querySelector('link[href$="'+e+'"]')},c=function(e){var t,n,o,a,c,i,u={};if(t=e.sheet,!t)return u;n=t.cssRules?t.cssRules:t.rules;for(var l=0;n.length>l;l++)o=n[l].cssText,a=r+n[l].selectorText,c=o.split(");")[0].match(/US\-ASCII\,([^"']+)/),c&&c[1]&&(i=decodeURIComponent(c[1]),u[a]=i);return u},i=function(e){var t,o,a;o="data-grunticon-embed";for(var c in e)if(a=c.slice(r.length),t=n.querySelectorAll(a+"["+o+"]"),t.length)for(var i=0;t.length>i;i++)t[i].innerHTML=e[c],t[i].style.backgroundImage="none",t[i].removeAttribute(o);return t},u=function(t){"svg"===e.method&&o(function(){i(c(a(e.href))),"function"==typeof t&&t()})};e.embedIcons=i,e.getCSS=a,e.getIcons=c,e.ready=o,e.svgLoadedCallback=u,e.embedSVG=u})(grunticon,this);
                
                grunticon(["/theme/css/icons.data.svg.css", "/theme/css/icons.data.png.css", "/theme/css/icons.fallback.css"]);
            </script>
        <noscript><link href="/theme/css/icons.fallback.css" rel="stylesheet"></noscript>
        <!-- menu toggle javascript -->
        <script type="text/javascript">
            document.addEventListener("DOMContentLoaded", initMenu);
            
            function initMenu(){
                var menu = document.getElementById("menu");
                var menulink = document.getElementById("menu-link");
                menulink.addEventListener("click", function toggleMenu(){
                        window.event.preventDefault();
                        menulink.classList.toggle('active');
                        menu.classList.toggle('active');              
                    });
            };
        </script>
        <!-- 不蒜子 -->
        <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

    <meta name="description" content="<p>JSON：序列化，成员标签，反序列化；HTTP获取JSON：获取GitHub的issue信息，流式解码；文本模板：模板表达式，模板输出的过程，帮助函数Must；HTML模板：输出网页，template.HTML类型避免转义。</p>" />

    <meta name="tags" content="gopl" />
    <meta name="tags" content="json" />
    <meta name="tags" content="http" />
    <meta name="tags" content="github" />
  <!-- 替换部分base的样式，看文章时，要再宽一点，右边有很多空间可以撑开 -->
  <link rel="stylesheet" type="text/css" href="/theme/css/mycss/article.css" />

</head>
<body>
    <div role="banner" id="masthead">
        <header>
            <a href="/"><img src="/images/mowang.png" alt="McManus Logo"></a>
                <h1>来玩魔王的咚@骑士救兵</h1>
            <a href="#menu" id="menu-link">more stuff</a>
            <nav id="menu">
                <ul>
                        <li><a href="/tags">tags</a></li>
                            <li><a href="/category/cloud.html">Cloud</a></li>
                            <li><a href="/category/docker.html">Docker</a></li>
                            <li class="active"><a href="/category/go.html">Go</a></li>
                            <li><a href="/category/linux.html">Linux</a></li>
                            <li><a href="/category/python.html">Python</a></li>
                            <li><a href="/category/xue-xi-bi-ji.html">学习笔记</a></li>
                            <li><a href="/category/yun-wei-zi-dong-hua.html">运维自动化</a></li>
                </ul>
            </nav>
        </header>
    </div>
        <div class="page" role="main">
  <div class="article" role="article">
    <article>
        <footer>
            <a name="top"></a>
            <p>
              <time datetime=" 2020-07-07 15:00:00+08:00">
                <script>document.write(moment('2020-07-07 15:00:00+08:00').format('LL'));</script>
              </time>
              ~
              <time datetime=" 2020-07-07 15:00:00+08:00">
                <script>document.write(moment('2020-07-07 15:00:00+08:00').format('LL'));</script>
              </time>
            </p>
        </footer>
        <header>
          <h2>
            JSON、文本模板、HTML模板
          </h2>
        </header>
      <div class="content">
         <div class="toc">
<ul>
<li><a href="#json">JSON</a><ul>
<li><a href="#xu-lie-hua-shu-chu">序列化输出</a></li>
<li><a href="#fan-xu-lie-hua">反序列化</a></li>
</ul>
</li>
<li><a href="#web-ying-yong">Web 应用</a><ul>
<li><a href="#ding-yi-jie-gou-ti">定义结构体</a></li>
<li><a href="#qing-qiu-huo-qu-json-bing-jie-xi">请求获取JSON并解析</a></li>
<li><a href="#diao-yong-zhi-xing">调用执行</a></li>
</ul>
</li>
<li><a href="#wen-ben-mu-ban">文本模板</a><ul>
<li><a href="#wen-ben-ti-huan-ji-ben-yong-fa">文本替换(基本用法)</a></li>
<li><a href="#yu-fa">语法</a></li>
<li><a href="#mu-ban-biao-da-shi">模板表达式</a></li>
<li><a href="#mu-ban-shu-chu-de-guo-cheng">模板输出的过程</a></li>
<li><a href="#bang-zhu-han-shu-must">帮助函数 Must</a></li>
</ul>
</li>
<li><a href="#html-mu-ban">HTML 模板</a><ul>
<li><a href="#shi-yong-mu-ban-shu-chu-ye-mian">使用模板输出页面</a></li>
<li><a href="#templatehtml-lei-xing">template.HTML 类型</a></li>
</ul>
</li>
</ul>
</div>
<h3 id="json"><a class="toclink" href="#json">JSON</a></h3>
<p>JSON是一种发送和接收格式化信息的标准。JSON不是唯一的标准，XML、ASN.1 和 Google 的 Protocol Buffer 都是相似的标准。Go通过标准库 encoding/json、encoding/xml、encoding/asn1 和其他的库对这些格式的编码和解码提供了非常好的支持，这些库都拥有相同的API。  </p>
<h4 id="xu-lie-hua-shu-chu"><a class="toclink" href="#xu-lie-hua-shu-chu">序列化输出</a></h4>
<p>首先定义一组数据：</p>
<div class="highlight"><pre><span></span><code><span class="kd">type</span><span class="w"> </span><span class="nx">Movie</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">Title</span><span class="w">  </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">Year</span><span class="w">   </span><span class="kt">int</span><span class="w">  </span><span class="s">`json:&quot;released&quot;`</span><span class="w"></span>
<span class="w">    </span><span class="nx">Color</span><span class="w">  </span><span class="kt">bool</span><span class="w"> </span><span class="s">`json:&quot;color,omitempty&quot;`</span><span class="w"></span>
<span class="w">    </span><span class="nx">Actors</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">var</span><span class="w"> </span><span class="nx">movies</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">[]</span><span class="nx">Movie</span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="nx">Title</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;Casablanca&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">Year</span><span class="p">:</span><span class="w"> </span><span class="mi">1942</span><span class="p">,</span><span class="w"> </span><span class="nx">Color</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"></span>
<span class="w">        </span><span class="nx">Actors</span><span class="p">:</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">&quot;Humphrey Bogart&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Ingrid Bergman&quot;</span><span class="p">}},</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="nx">Title</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;Cool Hand Luke&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">Year</span><span class="p">:</span><span class="w"> </span><span class="mi">1967</span><span class="p">,</span><span class="w"> </span><span class="nx">Color</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span>
<span class="w">        </span><span class="nx">Actors</span><span class="p">:</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">&quot;Paul Newman&quot;</span><span class="p">}},</span><span class="w"></span>
<span class="w">    </span><span class="p">{</span><span class="nx">Title</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;Bullitt&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">Year</span><span class="p">:</span><span class="w"> </span><span class="mi">1968</span><span class="p">,</span><span class="w"> </span><span class="nx">Color</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w"></span>
<span class="w">        </span><span class="nx">Actors</span><span class="p">:</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">&quot;Steve McQueen&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Jacqueline Bisset&quot;</span><span class="p">}},</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>然后通过 json.Marshal 进行编码：</p>
<div class="highlight"><pre><span></span><code><span class="nx">data</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">json</span><span class="p">.</span><span class="nx">Marshal</span><span class="p">(</span><span class="nx">movies</span><span class="p">)</span><span class="w"></span>
<span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatalf</span><span class="p">(</span><span class="s">&quot;JSON Marshal failed: %s&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">&quot;%s\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">data</span><span class="p">)</span><span class="w"></span>

<span class="cm">/* 执行结果</span>
<span class="cm">[{&quot;Title&quot;:&quot;Casablanca&quot;,&quot;released&quot;:1942,&quot;Actors&quot;:[&quot;Humphrey Bogart&quot;,&quot;Ingrid Bergman&quot;]},{&quot;Title&quot;:&quot;Cool Hand Luke&quot;,&quot;released&quot;:1967,&quot;color&quot;:true,&quot;Actors&quot;:[&quot;Paul Newman&quot;]},{&quot;Title&quot;:&quot;Bullitt&quot;,&quot;released&quot;:1968,&quot;color&quot;:true,&quot;Actors&quot;:[&quot;Steve McQueen&quot;,&quot;Jacqueline Bisset&quot;]}]</span>
<span class="cm">*/</span><span class="w"></span>
</code></pre></div>

<p>这种紧凑的表示方法适合传输，但是不方便阅读。有一个 json.MarshalIndent 的变体可以输出整齐格式化过的结果。多传2个参数，第一个是定义每行输出的前缀字符串，第二个是定义缩进的字符串：</p>
<div class="highlight"><pre><span></span><code><span class="nx">data</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">json</span><span class="p">.</span><span class="nx">MarshalIndent</span><span class="p">(</span><span class="nx">movies</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;    &quot;</span><span class="p">)</span><span class="w"></span>
<span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatalf</span><span class="p">(</span><span class="s">&quot;JSON Marshal failed: %s&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">&quot;%s\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">data</span><span class="p">)</span><span class="w"></span>

<span class="cm">/* 执行结果</span>
<span class="cm">[</span>
<span class="cm">    {</span>
<span class="cm">        &quot;Title&quot;: &quot;Casablanca&quot;,</span>
<span class="cm">        &quot;released&quot;: 1942,</span>
<span class="cm">        &quot;Actors&quot;: [</span>
<span class="cm">            &quot;Humphrey Bogart&quot;,</span>
<span class="cm">            &quot;Ingrid Bergman&quot;</span>
<span class="cm">        ]</span>
<span class="cm">    },</span>
<span class="cm">    {</span>
<span class="cm">        &quot;Title&quot;: &quot;Cool Hand Luke&quot;,</span>
<span class="cm">        &quot;released&quot;: 1967,</span>
<span class="cm">        &quot;color&quot;: true,</span>
<span class="cm">        &quot;Actors&quot;: [</span>
<span class="cm">            &quot;Paul Newman&quot;</span>
<span class="cm">        ]</span>
<span class="cm">    },</span>
<span class="cm">    {</span>
<span class="cm">        &quot;Title&quot;: &quot;Bullitt&quot;,</span>
<span class="cm">        &quot;released&quot;: 1968,</span>
<span class="cm">        &quot;color&quot;: true,</span>
<span class="cm">        &quot;Actors&quot;: [</span>
<span class="cm">            &quot;Steve McQueen&quot;,</span>
<span class="cm">            &quot;Jacqueline Bisset&quot;</span>
<span class="cm">        ]</span>
<span class="cm">    }</span>
<span class="cm">]</span>
<span class="cm">*/</span><span class="w"></span>
</code></pre></div>

<p>只有可导出的成员可以转换为JSON字段，上面的例子中用的都是大写。<br>
<strong>成员标签</strong>（field tag），是结构体成员的编译期间关联的一些元素信息。标签值的第一部分指定了Go结构体成员对应的JSON中字段的名字。<br>
另外，Color标签还有一个额外的选项 omitempty，它表示如果这个成员的值是零值或者为空，则不输出这个成员到JSON中。所以Title为"Casablanca"的JSON里没有color。  </p>
<h4 id="fan-xu-lie-hua"><a class="toclink" href="#fan-xu-lie-hua">反序列化</a></h4>
<p>反序列化操作将JSON字符串解码为Go数据结构。这个是由 json.Unmarshal 实现的:</p>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">titles</span><span class="w"> </span><span class="p">[]</span><span class="kd">struct</span><span class="p">{</span><span class="w"> </span><span class="nx">Title</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">json</span><span class="p">.</span><span class="nx">Unmarshal</span><span class="p">(</span><span class="nx">data</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="nx">titles</span><span class="p">);</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatalf</span><span class="p">(</span><span class="s">&quot;JSON unmarshaling failed: %s&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">titles</span><span class="p">)</span><span class="w"></span>

<span class="cm">/* 执行结果</span>
<span class="cm">[{Casablanca} {Cool Hand Luke} {Bullitt}]</span>
<span class="cm">*/</span><span class="w"></span>
</code></pre></div>

<p>这里接收数据时定义的结构体只有一个Title字段，这样当函数 Unmarshal 调用完成后，将填充结构体切片中的 Title 值，而JSON中其他的字段就丢弃了。  </p>
<h3 id="web-ying-yong"><a class="toclink" href="#web-ying-yong">Web 应用</a></h3>
<p>很多的 Web 服务器都提供 JSON 接口，通过发送HTTP请求来获取想要得到的JSON信息。下面通过查询Github提供的 issue 跟踪接口来演示一下。  </p>
<h4 id="ding-yi-jie-gou-ti"><a class="toclink" href="#ding-yi-jie-gou-ti">定义结构体</a></h4>
<p>首先，定义好类型，顺便还有常量：</p>
<div class="highlight"><pre><span></span><code><span class="c1">// ch4/github/github.go</span><span class="w"></span>
<span class="c1">// https://api.github.com/ 提供了丰富的接口</span><span class="w"></span>
<span class="c1">// 提供查询GitHub的issue接口的API</span><span class="w"></span>
<span class="c1">// GitHub上有详细的API使用说明：https://developer.github.com/v3/search/#search-issues-and-pull-requests</span><span class="w"></span>
<span class="kn">package</span><span class="w"> </span><span class="nx">github</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="s">&quot;time&quot;</span><span class="w"></span>

<span class="kd">const</span><span class="w"> </span><span class="nx">IssuesURL</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">&quot;https://api.github.com/search/issues&quot;</span><span class="w"></span>

<span class="kd">type</span><span class="w"> </span><span class="nx">IssuesSearchResult</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">TotalCount</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="s">`json:&quot;total_count&quot;`</span><span class="w"></span>
<span class="w">    </span><span class="nx">Items</span><span class="w">      </span><span class="p">[]</span><span class="o">*</span><span class="nx">Issue</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">type</span><span class="w"> </span><span class="nx">Issue</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">Number</span><span class="w">   </span><span class="kt">int</span><span class="w"></span>
<span class="w">    </span><span class="nx">HTMLURL</span><span class="w">  </span><span class="kt">string</span><span class="w"> </span><span class="s">`json:&quot;html_url&quot;`</span><span class="w"></span>
<span class="w">    </span><span class="nx">Title</span><span class="w">    </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">State</span><span class="w">    </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">User</span><span class="w">     </span><span class="o">*</span><span class="nx">User</span><span class="w"></span>
<span class="w">    </span><span class="nx">CreateAt</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="w"> </span><span class="s">`json:&quot;created_at&quot;`</span><span class="w"></span>
<span class="w">    </span><span class="nx">Body</span><span class="w">     </span><span class="kt">string</span><span class="w">    </span><span class="c1">// Markdown 格式</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">type</span><span class="w"> </span><span class="nx">User</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">Login</span><span class="w">   </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">HTMLURL</span><span class="w"> </span><span class="kt">string</span><span class="w"> </span><span class="s">`json:&quot;html_url&quot;`</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>关于字段名称，即使对应的JSON字段的名称都是小写的，但是结构体中的字段必须首字母大写（<em>不可导出的字段也无法把JSON数据导入</em>）。这种情况很普遍，这里可以偷个懒。在 Unmarshal 阶段，JSON字段的名称关联到Go结构体成员的名称是忽略大小写的，这里也不需要考虑序列化的问题，所以很多地方都不需要写成员标签。不过，小写的变量在需要分词的时候，可能会使用下划线分割，这种情况下，还是要用一下成员标签的。<br>
这里也是选择性地对JSON中的字段进行解码，因为相对于这里演示的内容，GitHub的查询返回的信息是相当多的。  </p>
<h4 id="qing-qiu-huo-qu-json-bing-jie-xi"><a class="toclink" href="#qing-qiu-huo-qu-json-bing-jie-xi">请求获取JSON并解析</a></h4>
<p>函数 SearchIssues 发送HTTP请求并将返回的JSON字符串进行解析。<br>
关于Get请求的参数，参数中可能会出现URL格式里的特殊字符，比如 ?、&amp;。因此要使用 url.QueryEscape 函数进行转义。  </p>
<div class="highlight"><pre><span></span><code><span class="c1">// ch4/github/search.go</span><span class="w"></span>
<span class="kn">package</span><span class="w"> </span><span class="nx">github</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;encoding/json&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;fmt&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;net/http&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;net/url&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;strings&quot;</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="c1">// 查询GitHub的issue接口</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">SearchIssues</span><span class="p">(</span><span class="nx">terms</span><span class="w"> </span><span class="p">[]</span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="nx">IssuesSearchResult</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">q</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">url</span><span class="p">.</span><span class="nx">QueryEscape</span><span class="p">(</span><span class="nx">strings</span><span class="p">.</span><span class="nx">Join</span><span class="p">(</span><span class="nx">terms</span><span class="p">,</span><span class="w"> </span><span class="s">&quot; &quot;</span><span class="p">))</span><span class="w"></span>
<span class="w">    </span><span class="nx">resp</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">Get</span><span class="p">(</span><span class="nx">IssuesURL</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s">&quot;?q=&quot;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">q</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">defer</span><span class="w"> </span><span class="nx">resp</span><span class="p">.</span><span class="nx">Body</span><span class="p">.</span><span class="nx">Close</span><span class="p">()</span><span class="w"></span>

<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">resp</span><span class="p">.</span><span class="nx">StatusCode</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">StatusOK</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="p">,</span><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Errorf</span><span class="p">(</span><span class="s">&quot;search query failed: %s&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">resp</span><span class="p">.</span><span class="nx">Status</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>

<span class="w">    </span><span class="kd">var</span><span class="w"> </span><span class="nx">result</span><span class="w"> </span><span class="nx">IssuesSearchResult</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">json</span><span class="p">.</span><span class="nx">NewDecoder</span><span class="p">(</span><span class="nx">resp</span><span class="p">.</span><span class="nx">Body</span><span class="p">).</span><span class="nx">Decode</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">result</span><span class="p">);</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="o">&amp;</span><span class="nx">result</span><span class="p">,</span><span class="w"> </span><span class="kc">nil</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p><strong>流式解码噐</strong><br>
之前是使用 json.Unmarshal 进行解码，而这里使用流式解码噐。它可以依次从字节流中解码出多个JSON实体，不过这里没有用到该功能。另外还有对应的 json.Encoder 的流式编码器。<br>
调用 Decode 方法后，就完成了对变量 result 的填充。  </p>
<h4 id="diao-yong-zhi-xing"><a class="toclink" href="#diao-yong-zhi-xing">调用执行</a></h4>
<p>最后就是将 result 中的内容进行格式化输出，这里用了固定宽度的方法将结果输出为类似表格的形式：</p>
<div class="highlight"><pre><span></span><code><span class="c1">// ch4/issues/main.go</span><span class="w"></span>
<span class="c1">// 将符合条件的issue输出为一个表格</span><span class="w"></span>
<span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;fmt&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;gopl/ch4/github&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;log&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;os&quot;</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">result</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">github</span><span class="p">.</span><span class="nx">SearchIssues</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">[</span><span class="mi">1</span><span class="p">:])</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">&quot;%d issue: \n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">TotalCount</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">item</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">result</span><span class="p">.</span><span class="nx">Items</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Printf</span><span class="p">(</span><span class="s">&quot;#%-5d %9.9s %.55s\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">item</span><span class="p">.</span><span class="nx">Number</span><span class="p">,</span><span class="w"> </span><span class="nx">item</span><span class="p">.</span><span class="nx">User</span><span class="p">.</span><span class="nx">Login</span><span class="p">,</span><span class="w"> </span><span class="nx">item</span><span class="p">.</span><span class="nx">Title</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>使用命令行参数指定搜索条件，该命令搜索 Go 项目里的 issue 接口，查找 open 状态的列表。由于返回的还是很多，后面的参数是对内容再进行筛选：</p>
<div class="highlight"><pre><span></span><code>PS H:\Go\src\gopl\ch4\issues&gt; go run main.go repo:golang/go is:open json decoder tag
6 issue:
#28143 Carpetsmo proposal: encoding/json: add &quot;readonly&quot; tag
#14750 cyberphon encoding/json: parser ignores the case of member names
#17609 nathanjsw encoding/json: ambiguous fields are marshalled
#22816 ganelon13 encoding/json: include field name in unmarshal error me
#19348 davidlaza cmd/compile: enable mid-stack inlining
#19109  bradfitz proposal: cmd/go: make fuzzing a first class citizen, l
PS H:\Go\src\gopl\ch4\issues&gt;
</code></pre></div>

<h3 id="wen-ben-mu-ban"><a class="toclink" href="#wen-ben-mu-ban">文本模板</a></h3>
<p>进行简单的格式化输出，使用fmt包就足够了。但是要实现更复杂的格式化输出，并且有时候还要求格式和代码彻底分离。这可以通过 text/templat 包和 html/template 包里的方法来实现，通过这两个包，可以将程序变量的值代入到模板中。  </p>
<h4 id="wen-ben-ti-huan-ji-ben-yong-fa"><a class="toclink" href="#wen-ben-ti-huan-ji-ben-yong-fa">文本替换(基本用法)</a></h4>
<p>先准备一个简单的模板<code>index.html</code>：</p>
<div class="highlight"><pre><span></span><code><span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>Hello {{.Name}}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>Age: {{.Age}}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
</code></pre></div>

<p>然后在Go里使用模板：</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;fmt&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;os&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;text/template&quot;</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="kd">type</span><span class="w"> </span><span class="nx">Person</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">Name</span><span class="w"> </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">Age</span><span class="w"> </span><span class="kt">int</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">t</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">template</span><span class="p">.</span><span class="nx">ParseFiles</span><span class="p">(</span><span class="s">&quot;index.html&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;模板解析异常:&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">p</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">Person</span><span class="p">{</span><span class="s">&quot;Bob&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">32</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">Execute</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stdout</span><span class="p">,</span><span class="w"> </span><span class="nx">p</span><span class="p">);</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;模板加载数据异常:&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="cm">/* 执行结果</span>
<span class="cm">PS H:\Go\src\go_dev\day10\http\use_template&gt; go run main.go</span>
<span class="cm">&lt;p&gt;Hello Bob&lt;/p&gt;</span>
<span class="cm">&lt;p&gt;Age: 32&lt;/p&gt;</span>
<span class="cm">PS H:\Go\src\go_dev\day10\http\use_template&gt;</span>
<span class="cm">*/</span><span class="w"></span>
</code></pre></div>

<p>如果直接用 {{.}} 不加字段名的话，就是输出结构体打印的效果。  </p>
<h5 id="shu-chu-dao-liu-lan-qi-li"><a class="toclink" href="#shu-chu-dao-liu-lan-qi-li">输出到浏览器里</a></h5>
<p>要输出到浏览器里，只需要在 t.Execute(os.Stdout, p) 里，把原本输出到终端换成输出到处理函数的 w http.ResponseWriter 类型，就好了。
html模板的内容不变，下面是go的代码：</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;fmt&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;net/http&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;text/template&quot;</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">Hello</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span><span class="w"> </span><span class="nx">r</span><span class="w"> </span><span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintf</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Hello World&quot;</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">type</span><span class="w"> </span><span class="nx">Person</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">Name</span><span class="w"> </span><span class="kt">string</span><span class="w"></span>
<span class="w">    </span><span class="nx">Age</span><span class="w"> </span><span class="kt">int</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">Index</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span><span class="w"> </span><span class="nx">r</span><span class="w"> </span><span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">p</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">Person</span><span class="p">{</span><span class="s">&quot;Cara&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">18</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">t</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">template</span><span class="p">.</span><span class="nx">ParseFiles</span><span class="p">(</span><span class="s">&quot;index.html&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;加载模板ERROR:&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">t</span><span class="p">.</span><span class="nx">Execute</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="nx">p</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">http</span><span class="p">.</span><span class="nx">HandleFunc</span><span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">Hello</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">http</span><span class="p">.</span><span class="nx">HandleFunc</span><span class="p">(</span><span class="s">&quot;/index&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">Index</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ListenAndServe</span><span class="p">(</span><span class="s">&quot;0.0.0.0:8000&quot;</span><span class="p">,</span><span class="w"> </span><span class="kc">nil</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;http Listen failed&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="yu-fa"><a class="toclink" href="#yu-fa">语法</a></h4>
<p>下面列举了一下常用的语法。  </p>
<h5 id="pan-duan"><a class="toclink" href="#pan-duan">判断</a></h5>
<p>用法示例：</p>
<div class="highlight"><pre><span></span><code><span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
{{if gt .Age 18}}
<span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>已成年<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
{{else}}
<span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>未成年<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
{{end}}
<span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</code></pre></div>

<p>更多判断逻辑：
<strong>not 非</strong><br>
{{if not .condition}} <br>
{{end}}<br>
<strong>and 与</strong><br>
{{if and .condition1 .condition2}} <br>
{{end}}<br>
<strong>or 或</strong><br>
{{if or .condition1 .condition2}} <br>
{{end}}<br>
<strong>eq 等于</strong><br>
{{if eq .var1 .var2}} <br>
{{end}}<br>
<strong>ne 不等于</strong><br>
{{if ne .var1 .var2}} <br>
{{end}}<br>
<strong>lt 小于</strong><br>
{{if lt .var1 .var2}} <br>
{{end}}<br>
<strong>le 小于等于</strong><br>
{{if le .var1 .var2}} <br>
{{end}}<br>
<strong>gt 大于</strong><br>
{{if gt .var1 .var2}} <br>
{{end}}<br>
<strong>ge 大于等于</strong><br>
{{if ge .var1 .var2}} <br>
{{end}}  </p>
<h5 id="with-feng-zhuang"><a class="toclink" href="#with-feng-zhuang">with 封装</a></h5>
<p>with语句就是创建一个封闭的作用域，在其范围内，{{.}}代表with的变量，而与外面的{{.}}无关，只与with的参数有关：</p>
<div class="highlight"><pre><span></span><code><span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
{{with .Name}}
<span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>{{.}}<span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
{{end}}
<span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
</code></pre></div>

<p>上面这样包在 {{with .Var}} 里，with 里的 {{.}} 代表的就是 Var 这个变量。<br>
with 可以封装常数：</p>
<div class="highlight"><pre><span></span><code>{{ with &quot;world&quot;}}
    Now the dot is set to {{ . }}
{{ end }}
</code></pre></div>

<h5 id="xun-huan-bian-li"><a class="toclink" href="#xun-huan-bian-li">循环（遍历）</a></h5>
<p>golang的template支持range循环来遍历map、slice内的内容，在range循环内，还可以使用$设置循环变量，我们可以通过 $i $v 来访问遍历的值。语法为：</p>
<div class="highlight"><pre><span></span><code>{{range $i, $v := .slice}}
    <span class="p">&lt;</span><span class="nt">li</span><span class="p">&gt;</span>key: {{ $key }}, value: {{ $value }}<span class="p">&lt;/</span><span class="nt">li</span><span class="p">&gt;</span>
{{end}}
</code></pre></div>

<p>这是另外一种遍历方式，这种方式无法访问到index或者key的值，需要通过点来访问对应的value：</p>
<div class="highlight"><pre><span></span><code>{{range .slice}}
{{.field}}
{{end}}
</code></pre></div>

<p>在循环内，点是代表遍历的值。原本使用点来访问的变量，那么在循环内部就要用 $. 来访问。下面的例子表示循环内和循环外 ArticleConten 这个变量访问的方式：</p>
<div class="highlight"><pre><span></span><code>{{.ArticleContent}}
{{range .slice}}
{{$.ArticleContent}}
{{end}}
</code></pre></div>

<h5 id="ding-yi-bian-liang"><a class="toclink" href="#ding-yi-bian-liang">定义变量</a></h5>
<p>模板的参数可以是go中的基本数据类型，如字串，数字，布尔值，数组切片或者一个结构体。在模板中设置变量可以使用 $variable := value。我们在range迭代的过程使用了设置变量的方式。  </p>
<div class="highlight"><pre><span></span><code>{{$article := &quot;hello&quot;}}
{{$name := .Name}}
</code></pre></div>

<h4 id="mu-ban-biao-da-shi"><a class="toclink" href="#mu-ban-biao-da-shi">模板表达式</a></h4>
<p>模板，是一个字符串或者文件，它包含一个或者多个两边用双大括号包围的单元，这称为<strong>操作</strong>。大多数字符串是直接输出的，但是操作可以引发其他的行为。<br>
每个操作在模板语言里对应一个表达式，功能包括：</p>
<ul>
<li>输出值</li>
<li>选择结构体成员</li>
<li>调用函数和方法</li>
<li>描述控逻辑</li>
<li>实例化其他的模板</li>
</ul>
<p>继续使用 GitHub 的 issue 接口返回的数据，这次使用模板来输出。一个简单的字符串模板如下所示：</p>
<div class="highlight"><pre><span></span><code><span class="kd">const</span><span class="w"> </span><span class="nx">templ</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">`{{.TotalCount}} issues:</span>
<span class="s">{{range .Items}}----------------------------------------</span>
<span class="s">Number: {{.Number}}</span>
<span class="s">User:   {{.User.Login}}</span>
<span class="s">Title:  {{.Title | printf &quot;%.64s&quot;}}</span>
<span class="s">Age:    {{.CreatedAt | daysAgo}} days</span>
<span class="s">{{end}}`</span><span class="w"></span>
</code></pre></div>

<p>点号（.）表示当前值的标记。最开始的时候表示模板里的参数，也就是 github.IssuesSearchResult。<br>
操作 {{.TotalCount}} 就是 TotalCount 字段的值。<br>
{{range .Items}} 和 {{end}} 操作创建一个循环，这个循环内部的点号（.）表示Items里的每一个元素。<br>
在操作中，管道符（|）会将前一个操作的结果当做下一个操作的输入，这个和UNIX里的管道类似。<br>
<code>{{.Title | printf "%.64s"}}</code>，这里的第二个操作是printf函数，在包里这个名称对应的就是fmt.Sprintf，所以会按照fmt.Sprintf函数返回的样式输出。<br>
<code>{{.CreatedAt | daysAgo}}</code>，这里的第二个操作数是 daysAgo，这是一个自定义的函数，具体如下：</p>
<div class="highlight"><pre><span></span><code><span class="kd">func</span><span class="w"> </span><span class="nx">daysAgo</span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nb">int</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Since</span><span class="p">(</span><span class="nx">t</span><span class="p">).</span><span class="nx">Hours</span><span class="p">()</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">24</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="mu-ban-shu-chu-de-guo-cheng"><a class="toclink" href="#mu-ban-shu-chu-de-guo-cheng">模板输出的过程</a></h4>
<p>通过模板输出结果需要两个步骤：</p>
<ol>
<li>解析模板并转换为内部表示的方法</li>
<li>在指定的输入上执行（就是执行并输出）</li>
</ol>
<p>解析模板只需要执行一次。下面的代码创建并解析上面定义的文本模板：</p>
<div class="highlight"><pre><span></span><code><span class="nx">report</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">template</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">&quot;report&quot;</span><span class="p">).</span><span class="w"></span>
<span class="w">    </span><span class="nx">Funcs</span><span class="p">(</span><span class="nx">template</span><span class="p">.</span><span class="nx">FuncMap</span><span class="p">{</span><span class="s">&quot;daysAgo&quot;</span><span class="p">:</span><span class="w"> </span><span class="nx">daysAgo</span><span class="p">}).</span><span class="w"></span>
<span class="w">    </span><span class="nx">Parse</span><span class="p">(</span><span class="nx">templ</span><span class="p">)</span><span class="w"></span>
<span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>这里使用了方法的链式调用。template.New 函数创建并返回一个新的模板。<br>
Funcs 方法将自定义的 daysAgo 函数到内部的函数列表中。之前提到的printf实际对应的是fmt.Sprintf，也是在包内默认就已经在这个函数列表里了。如果有更多的自定义函数，就多次调用这个方法添加。<br>
最后就是调用Parse进行解析。<br>
上面的代码完成了创建模板，添加内部可调用的 daysAgo 函数，解析（Parse方法），检查（检查err是否为空）。现在就可以调用report的 Execute 方法，传入数据源（github.IssuesSearchResult，这个需要先调用github.SearchIssues函数来获取），并指定输出目标（使用 os.Stdout）：</p>
<div class="highlight"><pre><span></span><code><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">report</span><span class="p">.</span><span class="nx">Execute</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stdout</span><span class="p">,</span><span class="w"> </span><span class="nx">result</span><span class="p">);</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>之前的代码比较凌乱，下面出完整可运行的代码：</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;log&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;os&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;text/template&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;time&quot;</span><span class="w"></span>

<span class="w">    </span><span class="s">&quot;gopl/ch4/github&quot;</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="kd">const</span><span class="w"> </span><span class="nx">templ</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">`{{.TotalCount}} issues:</span>
<span class="s">{{range .Items}}----------------------------------------</span>
<span class="s">Number: {{.Number}}</span>
<span class="s">User:   {{.User.Login}}</span>
<span class="s">Title:  {{.Title | printf &quot;%.64s&quot;}}</span>
<span class="s">Age:    {{.CreatedAt | daysAgo}} days</span>
<span class="s">{{end}}`</span><span class="w"></span>

<span class="c1">// 自定义输出格式的方法</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">daysAgo</span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nb">int</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Since</span><span class="p">(</span><span class="nx">t</span><span class="p">).</span><span class="nx">Hours</span><span class="p">()</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">24</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="c1">// 解析模板</span><span class="w"></span>
<span class="w">    </span><span class="nx">report</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">template</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">&quot;report&quot;</span><span class="p">).</span><span class="w"></span>
<span class="w">        </span><span class="nx">Funcs</span><span class="p">(</span><span class="nx">template</span><span class="p">.</span><span class="nx">FuncMap</span><span class="p">{</span><span class="s">&quot;daysAgo&quot;</span><span class="p">:</span><span class="w"> </span><span class="nx">daysAgo</span><span class="p">}).</span><span class="w"></span>
<span class="w">        </span><span class="nx">Parse</span><span class="p">(</span><span class="nx">templ</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="c1">// 获取数据</span><span class="w"></span>
<span class="w">    </span><span class="nx">result</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">github</span><span class="p">.</span><span class="nx">SearchIssues</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">[</span><span class="mi">1</span><span class="p">:])</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="c1">// 输出</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">report</span><span class="p">.</span><span class="nx">Execute</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stdout</span><span class="p">,</span><span class="w"> </span><span class="nx">result</span><span class="p">);</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>这个版本还可以改善，下面对解析错误的处理进行了改进。  </p>
<h4 id="bang-zhu-han-shu-must"><a class="toclink" href="#bang-zhu-han-shu-must">帮助函数 Must</a></h4>
<p>由于目标通常是在编译期间就固定下来的，因此无法解析将会是一个严重的bug。上面的版本如果无法解析（去掉个大括号试试），只会以比较温和的方式报告出来。<br>
这里推荐使用帮助函数 template.Must，模板错误会Panic：</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;log&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;os&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;text/template&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;time&quot;</span><span class="w"></span>

<span class="w">    </span><span class="s">&quot;gopl/ch4/github&quot;</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="kd">const</span><span class="w"> </span><span class="nx">templ</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">`{{.TotalCount}} issues:</span>
<span class="s">{{range .Items}}----------------------------------------</span>
<span class="s">Number: {{.Number}}</span>
<span class="s">User:   {{.User.Login}}</span>
<span class="s">Title:  {{.Title | printf &quot;%.64s&quot;}}</span>
<span class="s">Age:    {{.CreatedAt | daysAgo}} days</span>
<span class="s">{{end}}`</span><span class="w"></span>

<span class="c1">// 自定义输出格式的方法</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">daysAgo</span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="nx">time</span><span class="p">.</span><span class="nx">Time</span><span class="p">)</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nb">int</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Since</span><span class="p">(</span><span class="nx">t</span><span class="p">).</span><span class="nx">Hours</span><span class="p">()</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">24</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="c1">// 使用帮助函数</span><span class="w"></span>
<span class="kd">var</span><span class="w"> </span><span class="nx">report</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">template</span><span class="p">.</span><span class="nx">Must</span><span class="p">(</span><span class="nx">template</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">&quot;issuelist&quot;</span><span class="p">).</span><span class="w"></span>
<span class="w">    </span><span class="nx">Funcs</span><span class="p">(</span><span class="nx">template</span><span class="p">.</span><span class="nx">FuncMap</span><span class="p">{</span><span class="s">&quot;daysAgo&quot;</span><span class="p">:</span><span class="w"> </span><span class="nx">daysAgo</span><span class="p">}).</span><span class="w"></span>
<span class="w">    </span><span class="nx">Parse</span><span class="p">(</span><span class="nx">templ</span><span class="p">))</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">result</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">github</span><span class="p">.</span><span class="nx">SearchIssues</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">[</span><span class="mi">1</span><span class="p">:])</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">report</span><span class="p">.</span><span class="nx">Execute</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stdout</span><span class="p">,</span><span class="w"> </span><span class="nx">result</span><span class="p">);</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>和上个版本的区别就是解析的过程外再包了一层 template.Must 函数。而效果就是原本解析错误是调用 <code>log.Fatal(err)</code> 来退出，这个调用也是自己的代码里指定的。<br>
而现在是调用 <code>panic(err)</code> 来退出，并且会看到一个更加严重的错误报告（错误信息是一样的），并且这个也是包内部提供的并且推荐的做法。<br>
最后是输出的结果：</p>
<div class="highlight"><pre><span></span><code>PS H:\Go\src\gopl\ch4\issuesreport&gt; go run main.go repo:golang/go is:open json decoder tag
6 issues:
----------------------------------------
Number: 28143
User:   Carpetsmoker
Title:  proposal: encoding/json: add &quot;readonly&quot; tag
Age:    135 days
----------------------------------------
Number: 14750
User:   cyberphone
Title:  encoding/json: parser ignores the case of member names
Age:    1079 days
----------------------------------------
...
</code></pre></div>

<h3 id="html-mu-ban"><a class="toclink" href="#html-mu-ban">HTML 模板</a></h3>
<p>接着看 html/template 包。它使用和 text/template 包里一样的 API 和表达式语法，并且额外地对出现在 HTML、JavaScript、CSS 和 URL 中的字符串进行自动转义。这样可以避免在生成 HTML 是引发一些安全问题。  </p>
<h4 id="shi-yong-mu-ban-shu-chu-ye-mian"><a class="toclink" href="#shi-yong-mu-ban-shu-chu-ye-mian">使用模板输出页面</a></h4>
<p>下面是一个将 issue 输出为 HTML 表格代码。由于两个包里的API是一样的，所以除了模板本身以外，GO代码没有太大的差别：</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;fmt&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;log&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;net/http&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;os&quot;</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;gopl/ch4/github&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;html/template&quot;</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="kd">var</span><span class="w"> </span><span class="nx">issueList</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">template</span><span class="p">.</span><span class="nx">Must</span><span class="p">(</span><span class="nx">template</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">&quot;issuelist&quot;</span><span class="p">).</span><span class="nx">Parse</span><span class="p">(</span><span class="s">`</span>
<span class="s">&lt;h1&gt;{{.TotalCount}} issues&lt;/h1&gt;</span>
<span class="s">&lt;table&gt;</span>
<span class="s">&lt;tr style=&#39;text-align: left&#39;&gt;</span>
<span class="s">  &lt;th&gt;#&lt;/th&gt;</span>
<span class="s">  &lt;th&gt;State&lt;/th&gt;</span>
<span class="s">  &lt;th&gt;User&lt;/th&gt;</span>
<span class="s">  &lt;th&gt;Title&lt;/th&gt;</span>
<span class="s">&lt;/tr&gt;</span>
<span class="s">{{range .Items}}</span>
<span class="s">&lt;tr&gt;</span>
<span class="s">  &lt;td&gt;&lt;a href=&#39;{{.HTMLURL}}&#39;&gt;{{.Number}}&lt;/a&gt;&lt;/td&gt;</span>
<span class="s">  &lt;td&gt;{{.State}}&lt;/td&gt;</span>
<span class="s">  &lt;td&gt;&lt;a href=&#39;{{.User.HTMLURL}}&#39;&gt;{{.User.Login}}&lt;/a&gt;&lt;/td&gt;</span>
<span class="s">  &lt;td&gt;{{.Title}}&lt;/td&gt;</span>
<span class="s">&lt;/tr&gt;</span>
<span class="s">{{end}}</span>
<span class="s">&lt;/table&gt;</span>
<span class="s">`</span><span class="p">))</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">result</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">github</span><span class="p">.</span><span class="nx">SearchIssues</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">[</span><span class="mi">1</span><span class="p">:])</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;http://localhost:8000&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">handler</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span><span class="w"> </span><span class="nx">r</span><span class="w"> </span><span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">showIssue</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="nx">result</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">http</span><span class="p">.</span><span class="nx">HandleFunc</span><span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">handler</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">ListenAndServe</span><span class="p">(</span><span class="s">&quot;localhost:8000&quot;</span><span class="p">,</span><span class="w"> </span><span class="kc">nil</span><span class="p">))</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">showIssue</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span><span class="w"> </span><span class="nx">result</span><span class="w"> </span><span class="o">*</span><span class="nx">github</span><span class="p">.</span><span class="nx">IssuesSearchResult</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">issueList</span><span class="p">.</span><span class="nx">Execute</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="nx">result</span><span class="p">);</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="templatehtml-lei-xing"><a class="toclink" href="#templatehtml-lei-xing">template.HTML 类型</a></h4>
<p>通过模板的操作导入的字符串，默认都会按照原样显示出来。就是会把HTML的特殊字符自动进行转义，效果就是无法通过模板导入的内容生成html标签。<br>
如果就是需要通过模板的操作再导入一些HTML的内容，就需要使用 template.HTML 类型。使用 template.HTML 类型后，可以避免模板自动转义受信任的 HTML 数据。同样的类型还有 template.CSS、template.JS、template.URL 等，具体可以查看源码。<br>
下面的操作演示了普通的 string 类型和 template.HTML 类型在导入一个 HTML 标签后显示效果的差别：</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;fmt&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;html/template&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;log&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;net/http&quot;</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="nx">templ</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">`&lt;p&gt;A: {{.A}}&lt;/p&gt;&lt;p&gt;B: {{.B}}&lt;/p&gt;`</span><span class="w"></span>
<span class="w">    </span><span class="nx">t</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">template</span><span class="p">.</span><span class="nx">Must</span><span class="p">(</span><span class="nx">template</span><span class="p">.</span><span class="nx">New</span><span class="p">(</span><span class="s">&quot;escape&quot;</span><span class="p">).</span><span class="nx">Parse</span><span class="p">(</span><span class="nx">templ</span><span class="p">))</span><span class="w"></span>
<span class="w">    </span><span class="kd">var</span><span class="w"> </span><span class="nx">data</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">A</span><span class="w"> </span><span class="kt">string</span><span class="w">        </span><span class="c1">// 不受信任的纯文本</span><span class="w"></span>
<span class="w">        </span><span class="nx">B</span><span class="w"> </span><span class="nx">template</span><span class="p">.</span><span class="nx">HTML</span><span class="w"> </span><span class="c1">// 受信任的HTML</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">data</span><span class="p">.</span><span class="nx">A</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">&quot;&lt;b&gt;Hello!&lt;/b&gt;&quot;</span><span class="w"></span>
<span class="w">    </span><span class="nx">data</span><span class="p">.</span><span class="nx">B</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">&quot;&lt;b&gt;Hello!&lt;/b&gt;&quot;</span><span class="w"></span>

<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;http://localhost:8000&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">handler</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span><span class="w"> </span><span class="nx">r</span><span class="w"> </span><span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nx">Execute</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="nx">data</span><span class="p">);</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">http</span><span class="p">.</span><span class="nx">HandleFunc</span><span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">handler</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">ListenAndServe</span><span class="p">(</span><span class="s">&quot;localhost:8000&quot;</span><span class="p">,</span><span class="w"> </span><span class="kc">nil</span><span class="p">))</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
      </div>
      <div class="back-to-top">
        <a href="/">HOME</a>
        <a href="#top">TOP</a>
      </div>
    </article>
  </div>
<!-- end article -->
<!-- 页面往下滚动一段之后才会显示TOC -->
<script>
  window.onscroll = function() {
    var tocbox = document.getElementsByClassName('toc')[0];
    var osTop = document.documentElement.scrollTop || document.body.scrollTop;
    var osWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
    // console.log(osTop)
    if (osTop>300 && osWidth>865) {
      tocbox.style.display = "block"
    }
    if (osTop<300 || osWidth<865) {
      tocbox.style.display = "none"
    }
  }
</script>
                <footer>
                    <div class="icons">
                    </div>
                    <span id="busuanzi_container_page_pv" style="padding: 10px">本文阅读量<span id="busuanzi_value_page_pv"></span>次</span>
                    <span id="busuanzi_container_site_pv" style="padding: 10px">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
                    <span id="busuanzi_container_site_uv" style="padding: 10px">本站总访客数<span id="busuanzi_value_site_uv"></span>人</span>
                    <p>© <script>document.write(moment().format('YYYY'));</script> 749B</p>
                </footer>
        </div>
</body>
</html>